from computing import *  # 迭代计算模块
from transmittance import *  # 传递系数模块
'''
该模块负责迭代计算
'''


def compute_loop(loop_count, x_step, time_step, max_error, T, W, s_coe_all, boundary_out, boundary_in):
    # 数据取值（分别为密度，导热系数，比热容，平衡曲线系数abc，传质扩散系数def，材料类型[0表示空气]）
    [den_m, conductivity_m, capacity_m, a, b, c, d, e, f, m_type] = s_coe_all
    [T_out,  W_out,  i_out, v_out, r_out] = boundary_out
    [T_in, W_in, i_in, v_in, r_in] = boundary_in

    # 初始化温湿度源项
    x_grid = len(s_coe_all[0])
    sp_T = np.zeros(x_grid, dtype=float)  # 创建源项1（温度场）
    sp_W = np.zeros(x_grid, dtype=float)  # 创建源项2（湿度场）
    # 保留上一时刻的温湿度场用于下一时刻的计算
    T0 = np.array(T, dtype=float)
    W0 = np.array(W, dtype=float)

    # 边界条件读取完毕，进行迭代计算
    # 计算下一时刻的温湿度分布
    for j in range(int(loop_count)):
        # 1.迭代计算保留上一次的计算值，用于收敛判断
        T_last = np.array(T)
        W_last = np.array(W)

        # 2.计算温度场
        # 2.1 更新温度场计算系数a,b,c
        a_T, b_T, c_T = coefficients_T(T, W, den_m, conductivity_m, capacity_m, d, e, f, m_type)
        # 2.2 更新温度场源项sp
        # 2.2.1 室外侧（左侧，x=0处）源项计算
        h_out = 8
        q_out = q_total(h_out, T_out, T[0], W_out, W[0], i_out, alpha=0.6)
        sp_T[0] = q_out
        # sp_T[0] = 0
        # 2.2.2 室内侧（右侧，x=L处）源项计算
        h_in = 3
        q_in = q_total(h_in, T_in, T[-1], W_in, W[-1], i_in, alpha=0.6)
        sp_T[-1] = q_in
        # sp_T[-1] = 0
        # 2.2.3 墙体内部源项计算
        # ——————待完善——————
        # 2.3 温度场计算
        T = compute(a_T, b_T, c_T, x_step, time_step, T0, W, sp_T)

        # 3.计算湿度场
        # 3.1 更新湿度场系数a,b,c
        a_W, b_W, c_W = coefficients_W(T, W, den_m, a, b, c, d, e, f, m_type)
        # 3.2 更新边界条件及源项
        # 3.2.1 室外侧（左侧，x=0处）源项计算
        hm_out = h_j(h_out)
        sp_W[0] = j_convection(hm_out, T_out, T[0], W_out, W[0])

        # 3.2.2 室内侧（右侧，x=L处）源项计算
        hm_in = h_j(h_in)
        sp_W[-1] = j_convection(hm_in, T_in, T[-1], W_in, W[-1])

        # 3.3 湿度场计算
        W = compute(a_W, b_W, c_W, x_step, time_step, W0, T, sp_W)
        # 3.4 湿度场校正：将湿度场限制在（0,1）以内
        W[W > 1] = 1.0  # 湿度场内大于1的限制在1
        W[W <= 0] = 0.0001  # 湿度场小于0的设置为0.0001

        # 4.循环校验
        error_T = np.max(np.abs(T - T_last)) / np.max(T)  # 计算温度场最大的相对误差
        error_W = np.max(np.abs(W - W_last)) / np.max(W)  # 计算湿度场最大的相对误差
        error = np.max([error_T, error_W])  # 取最大的相对误差

        if error < max_error:  # 判断误差是否合理，若误差小于最大误差限，跳出内循环
            # print('迭代次数：%d次；误差：%.2e ' % (j + 1, error))
            break  # 停止本次运算，进入下一时刻的温湿度计算

        # 循环过程中的异常处理，还有其它异常情况需要处理--------------------------
        elif np.isnan(error):
            print('NAN异常，迭代出现发散，准备调整时间步长')
            raise RuntimeError
        elif j == loop_count - 1:  # 输出达到最大设置循环次数时，进行子循环计算
            print('最大次数异常，步长/10，进入子循环')
            T, W = compute_loop_max(loop_count, x_step, time_step, max_error, T0, W0, s_coe_all,
                                    boundary_out, boundary_in)

    return T, W, sp_T[0], sp_T[-1], sp_W[0], sp_W[-1]


# 程序试运算代码，保证迭代时，不发生发散现象，返回合理的时间步长
def compute_loop_try(loop_count, x_step, time_step, max_error, T, W, s_coe_all, boundary_out, boundary_in):
    time_temp = time_step
    while True:
        try:  # 试运行
            compute_loop(loop_count, x_step, time_temp, max_error, T, W, s_coe_all, boundary_out, boundary_in)
            break  # 运行成功，则退出运行
        except Exception as e:
            print('试运行发生错误，代码:{}'.format(e))
            time_temp -= 1
            print('时间步长减少1s', end='')
            print('调整后的时间步长为：{}s'.format(time_temp))
            # 时间步长减到0之后，提示出错并退出程序
            if time_temp <= 0:
                print('时间步长小于0，请查找相关错误！')
                exit(1)
    return time_temp


# 当运行过程中，出现迭代次数达到最大时，仍未达到要求误差，分次进行计算
def compute_loop_max(loop_count, x_step, time_step, max_error, T, W, s_coe_all, boundary_out, boundary_in):
    n = 10
    time_step /= n
    for k in range(n):
        # print('正在进行第%d次子循环：' % (k + 1), end='')
        T, W, q_out, q_in, j_out, j_in = compute_loop(loop_count, x_step, time_step, max_error, T, W,
                                                      s_coe_all, boundary_out, boundary_in)
        # print('第%d次子循环完毕！' % (k + 1))
    return T, W


